package com.sakura.oj.sandbox.utils;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import com.sakura.oj.sandbox.constants.JudgeConstant;
import com.sakura.oj.sandbox.model.ExecuteMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StopWatch;

import java.io.*;
import java.nio.charset.StandardCharsets;

/**
 * 进程工具类
 */
@Slf4j
public class ProcessUtil {

    /**
     * 获取执行信息
     * @param process 进程
     * @return 执行信息
     */
    public static ExecuteMessage getExecuteMessage(Process process) {
        ExecuteMessage executeMessage = new ExecuteMessage();

        try {
            // 3.2) 等待编译完成
            int exitCode = process.waitFor();
            executeMessage.setExitCode(exitCode);
            if (exitCode != JudgeConstant.NORMAL_EXIT_CODE) {
                log.info("执行失败");
                BufferedReader bufferedReader = IoUtil.getReader(new InputStreamReader(process.getErrorStream(), StandardCharsets.UTF_8));
                String errorLine;
                StringBuilder outputSb = new StringBuilder();
                while ((errorLine = bufferedReader.readLine()) != null) {
                    outputSb.append(errorLine);
                }
                executeMessage.setErrorMessage(outputSb.toString());
                return executeMessage;
            }
            log.info("执行成功");
            // 获取执行成功的信息
            BufferedReader bufferedReader = IoUtil.getReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8));
            String line;
            StringBuilder outputSb = new StringBuilder();
            while ((line = bufferedReader.readLine()) != null) {
                outputSb.append(line);
            }
            executeMessage.setMessage(outputSb.toString());
            return executeMessage;
        } catch (IOException | InterruptedException e) {
            e.fillInStackTrace();
        }
        return executeMessage;
    }

    /**
     * 获取交互执行信息
     * @param process 进程
     * @return 执行信息
     */
    public static ExecuteMessage interactgetExecuteMessage(Process process, String args) {
        ExecuteMessage executeMessage = new ExecuteMessage();
        StopWatch stopWatch = new StopWatch();
        try {

            // 开始填写输入用例
            OutputStream outputStream = process.getOutputStream();
            OutputStreamWriter streamWriter = new OutputStreamWriter(outputStream);
            String[] s = args.split(" ");
            String s1 = StrUtil.join("\n", s) + '\n';
            streamWriter.write(s1);
            streamWriter.flush();

            // 开始计时
            stopWatch.start();
            // 等待进程执行完成并获取exitCode
            int exitCode = process.waitFor();
            executeMessage.setExitCode(exitCode);
            // 结束计时
            stopWatch.stop();
            executeMessage.setTime(stopWatch.getLastTaskTimeMillis());
            
            if (exitCode != JudgeConstant.NORMAL_EXIT_CODE) {
                log.info("执行失败");
                // 读取错误流
                InputStream errorStream = process.getErrorStream();
                BufferedReader errorReader = new BufferedReader(new InputStreamReader(errorStream, StandardCharsets.UTF_8));
                StringBuilder errorBuilder = new StringBuilder();
                String errorLine;
                while ((errorLine = errorReader.readLine()) != null) {
                    errorBuilder.append(errorLine).append("\n");
                }
                executeMessage.setErrorMessage(errorBuilder.toString());
                
                // 释放资源
                errorReader.close();
                errorStream.close();
                streamWriter.close();
                outputStream.close();
                process.destroy();
                return executeMessage;
            }
            
            log.info("执行成功");
            // 读取标准输出流
            InputStream inputStream = process.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
            StringBuilder stringBuilder = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                stringBuilder.append(line).append("\n");
            }
            executeMessage.setMessage(stringBuilder.toString());

            // 释放资源
            streamWriter.close();
            outputStream.close();
            inputStream.close();
            reader.close();
            process.destroy();

            return executeMessage;
        } catch (Exception e) {
            log.info("运行异常", e);
            executeMessage.setExitCode(1);
            executeMessage.setErrorMessage(e.getMessage());
            executeMessage.setTime(JudgeConstant.TIME_OUT);
            executeMessage.setMemory(JudgeConstant.MEMORY_OUT);
        }
        return executeMessage;
    }
}
